Availability
+Check available dates for studio booking
+Booking Info
+Reservations can be made via email or the contact page.
We recommend booking at least 2 weeks in advance.
diff --git a/about.html b/about.html index aac0135..fe60a58 100644 --- a/about.html +++ b/about.html @@ -98,6 +98,7 @@
간편한 온라인 예약 또는 자주 묻는 질문을 확인해보세요
diff --git a/css/schedule.css b/css/schedule.css new file mode 100644 index 0000000..ef189d3 --- /dev/null +++ b/css/schedule.css @@ -0,0 +1,544 @@ +/* ======================================== + 예약 현황 페이지 전용 스타일 + ======================================== */ + +/* 스케줄 래퍼 */ +.schedule-wrapper { + max-width: 720px; + margin: 0 auto; +} + +/* 캘린더 카드 */ +.calendar-card { + background: var(--bg-white); + border-radius: var(--border-radius-lg); + box-shadow: var(--shadow-md); + overflow: hidden; + margin-bottom: var(--spacing-2xl); +} + +/* 캘린더 네비게이션 */ +.calendar-nav { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--spacing-xl) var(--spacing-2xl); + background: var(--gradient-main); +} + +.cal-nav-btn { + width: 38px; + height: 38px; + border: 2px solid rgba(255, 255, 255, 0.4); + background: rgba(255, 255, 255, 0.15); + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-sm); + color: white; + transition: var(--transition); + backdrop-filter: blur(4px); +} + +.cal-nav-btn:hover { + background: rgba(255, 255, 255, 0.3); + border-color: rgba(255, 255, 255, 0.7); + transform: scale(1.05); +} + +.cal-title { + font-size: var(--font-2xl); + font-weight: var(--font-weight-bold); + color: white; + text-align: center; + letter-spacing: 0.02em; +} + +/* 캘린더 그리드 */ +.cal-header { + display: grid; + grid-template-columns: repeat(7, 1fr); + background: var(--bg-gray); + border-bottom: 1px solid var(--border-color); +} + +.cal-header span { + padding: var(--spacing-md) var(--spacing-sm); + text-align: center; + font-size: var(--font-sm); + font-weight: var(--font-weight-semibold); + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.cal-body { + display: grid; + grid-template-columns: repeat(7, 1fr); +} + +/* 날짜 셀 */ +.cal-cell { + aspect-ratio: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + border-right: 1px solid var(--border-light); + border-bottom: 1px solid var(--border-light); + position: relative; + cursor: default; + transition: background var(--duration-fast) var(--ease-default); +} + +.cal-cell:nth-child(7n) { + border-right: none; +} + +.cal-cell .day-num { + font-size: var(--font-base); + font-weight: var(--font-weight-medium); + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all var(--duration-fast) var(--ease-default); +} + +/* 빈 셀 */ +.cal-cell.empty { + background: transparent; +} + +/* 지난 날짜 */ +.cal-cell.past .day-num { + color: var(--text-light); + opacity: 0.4; +} + +/* 오늘 */ +.cal-cell.today .day-num { + background: var(--primary-color); + color: var(--text-white); + font-weight: var(--font-weight-bold); + box-shadow: 0 2px 8px rgba(255, 136, 0, 0.4); +} + +/* 예약 가능 */ +.cal-cell.available .day-num { + color: var(--text-primary); + font-weight: var(--font-weight-medium); +} + +.cal-cell.available:hover { + background: rgba(16, 185, 129, 0.06); +} + +.cal-cell.available:hover .day-num { + background: rgba(16, 185, 129, 0.12); + color: var(--color-success); +} + +/* 예약 가능 표시 점 */ +.cal-cell.available::after { + content: ''; + position: absolute; + bottom: 6px; + left: 50%; + transform: translateX(-50%); + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--color-success); + opacity: 0.6; +} + +/* 예약 마감 */ +.cal-cell.booked .day-num { + color: var(--text-light); + text-decoration: line-through; + text-decoration-color: var(--color-danger); + opacity: 0.6; +} + +.cal-cell.booked::after { + content: ''; + position: absolute; + bottom: 6px; + left: 50%; + transform: translateX(-50%); + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--color-danger); +} + +/* 범례 */ +.calendar-legend { + display: flex; + justify-content: center; + gap: var(--spacing-2xl); + margin-bottom: var(--spacing-2xl); + flex-wrap: wrap; +} + +.legend-item { + display: flex; + align-items: center; + gap: var(--spacing-sm); + font-size: var(--font-sm); + color: var(--text-secondary); + font-weight: var(--font-weight-medium); +} + +.legend-dot { + width: 10px; + height: 10px; + border-radius: 50%; +} + +.legend-dot.available { + background: var(--color-success); + opacity: 0.6; +} + +.legend-dot.booked { + background: var(--color-danger); +} + +.legend-dot.past { + background: var(--text-light); + opacity: 0.4; +} + +/* 안내 카드 */ +.schedule-info-card { + background: var(--bg-white); + border-radius: var(--border-radius-lg); + box-shadow: var(--shadow-md); + padding: var(--spacing-2xl); + text-align: center; + border-top: 3px solid var(--primary-color); +} + +.schedule-info-card .info-icon { + width: 56px; + height: 56px; + display: inline-flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #fff4e6, #ffe8cc); + color: var(--primary-color); + border-radius: 50%; + font-size: 1.4rem; + margin-bottom: var(--spacing-lg); +} + +.schedule-info-card h3 { + font-size: var(--font-xl); + font-weight: var(--font-weight-bold); + color: var(--text-primary); + margin-bottom: var(--spacing-sm); +} + +.schedule-info-card p { + color: var(--text-secondary); + font-size: var(--font-sm); + margin-bottom: var(--spacing-xl); + line-height: var(--line-height-relaxed); +} + +.schedule-actions { + display: flex; + justify-content: center; + gap: var(--spacing-md); + flex-wrap: wrap; +} + +.schedule-actions .btn-primary { + display: inline-flex; + align-items: center; + gap: var(--spacing-sm); +} + +.schedule-actions .btn-secondary { + display: inline-flex; + align-items: center; + gap: var(--spacing-sm); +} + +/* 운영 정보 */ +.schedule-details { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-lg); + margin-top: var(--spacing-2xl); + padding-top: var(--spacing-xl); + border-top: 1px solid var(--border-light); +} + +.detail-item { + text-align: center; +} + +.detail-item .detail-label { + display: block; + font-size: var(--font-xs); + color: var(--text-light); + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: var(--spacing-xs); + font-weight: var(--font-weight-semibold); +} + +.detail-item .detail-value { + display: block; + font-size: var(--font-sm); + color: var(--text-primary); + font-weight: var(--font-weight-bold); +} + +/* 로딩 상태 - 그리드 위에 펄스 효과 */ +.cal-body.loading { + position: relative; +} + +.cal-body.loading::after { + content: ''; + position: absolute; + inset: 0; + background: rgba(255, 255, 255, 0.5); + animation: pulse 1.2s ease-in-out infinite; + pointer-events: none; + z-index: 1; +} + +@keyframes pulse { + 0%, 100% { opacity: 0.3; } + 50% { opacity: 0.6; } +} + +/* ======================================== + 반응형 디자인 + ======================================== */ +@media (max-width: 768px) { + .schedule-wrapper { + margin: 0 var(--spacing-sm); + } + + .calendar-nav { + padding: var(--spacing-lg) var(--spacing-xl); + } + + .cal-title { + font-size: var(--font-xl); + } + + .cal-header span { + padding: var(--spacing-sm); + font-size: var(--font-xs); + } + + .cal-cell .day-num { + font-size: var(--font-sm); + width: 30px; + height: 30px; + } + + .cal-cell.booked::after, + .cal-cell.available::after { + width: 4px; + height: 4px; + bottom: 3px; + } + + .calendar-legend { + gap: var(--spacing-lg); + } + + .legend-item { + font-size: var(--font-xs); + } + + .schedule-details { + grid-template-columns: 1fr; + gap: var(--spacing-md); + } + + .schedule-info-card { + padding: var(--spacing-xl); + } +} + +@media (max-width: 480px) { + .cal-nav-btn { + width: 32px; + height: 32px; + font-size: var(--font-xs); + } + + .calendar-nav { + padding: var(--spacing-md) var(--spacing-lg); + } + + .cal-title { + font-size: var(--font-lg); + } + + .cal-cell .day-num { + font-size: var(--font-xs); + width: 26px; + height: 26px; + } + + .cal-cell.booked::after, + .cal-cell.available::after { + width: 3px; + height: 3px; + bottom: 2px; + } +} + +/* ======================================== + 다크모드 + ======================================== */ +[data-theme="dark"] .calendar-card { + background: rgba(255, 255, 255, 0.04); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); +} + +[data-theme="dark"] .calendar-nav { + background: linear-gradient(135deg, #cc6d00, #b35500); +} + +[data-theme="dark"] .cal-header { + background: rgba(255, 255, 255, 0.06); + border-bottom-color: var(--glass-border); +} + +[data-theme="dark"] .cal-header span { + color: var(--dark-text-secondary); +} + +[data-theme="dark"] .cal-cell { + border-color: var(--glass-border); +} + +[data-theme="dark"] .cal-cell.past .day-num { + color: var(--dark-text-disabled); +} + +[data-theme="dark"] .cal-cell.today .day-num { + background: var(--primary-color); + color: white; + box-shadow: 0 2px 8px rgba(255, 136, 0, 0.5); +} + +[data-theme="dark"] .cal-cell.available .day-num { + color: var(--dark-text-primary); +} + +[data-theme="dark"] .cal-cell.available:hover { + background: rgba(52, 211, 153, 0.08); +} + +[data-theme="dark"] .cal-cell.available:hover .day-num { + background: rgba(52, 211, 153, 0.15); + color: #34d399; +} + +[data-theme="dark"] .cal-cell.available::after { + background: #34d399; +} + +[data-theme="dark"] .cal-cell.booked .day-num { + color: var(--dark-text-disabled); + text-decoration-color: #f87171; +} + +[data-theme="dark"] .cal-cell.booked::after { + background: #f87171; +} + +[data-theme="dark"] .cal-nav-btn { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.3); + color: white; +} + +[data-theme="dark"] .cal-nav-btn:hover { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.5); +} + +[data-theme="dark"] .legend-item { + color: var(--dark-text-secondary); +} + +[data-theme="dark"] .legend-dot.available { + background: #34d399; +} + +[data-theme="dark"] .legend-dot.booked { + background: #f87171; +} + +[data-theme="dark"] .legend-dot.past { + background: var(--dark-text-disabled); +} + +[data-theme="dark"] .schedule-info-card { + background: rgba(255, 255, 255, 0.04); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); + border-top-color: var(--primary-color); +} + +[data-theme="dark"] .schedule-info-card .info-icon { + background: rgba(255, 136, 0, 0.15); +} + +[data-theme="dark"] .schedule-info-card h3 { + color: var(--dark-text-primary); +} + +[data-theme="dark"] .schedule-info-card p { + color: var(--dark-text-secondary); +} + +[data-theme="dark"] .detail-item .detail-label { + color: var(--dark-text-tertiary); +} + +[data-theme="dark"] .detail-item .detail-value { + color: var(--dark-text-primary); +} + +[data-theme="dark"] .schedule-details { + border-top-color: var(--glass-border); +} + +[data-theme="dark"] .cal-body.loading::after { + background: rgba(0, 0, 0, 0.4); +} + +/* ======================================== + 접근성 + ======================================== */ +.cal-nav-btn:focus-visible { + outline: 2px solid white; + outline-offset: 2px; +} + +@media (prefers-reduced-motion: reduce) { + .cal-loading i { + animation: none; + } + + .cal-nav-btn:hover { + transform: none; + } +} diff --git a/en/about.html b/en/about.html index cd3fc95..8dd3b6b 100644 --- a/en/about.html +++ b/en/about.html @@ -104,6 +104,7 @@Make an easy online reservation or check our frequently asked questions
diff --git a/en/gallery.html b/en/gallery.html index 2382cfd..8fbe645 100644 --- a/en/gallery.html +++ b/en/gallery.html @@ -104,6 +104,7 @@Experience new creative possibilities at our professional motion capture studio
diff --git a/en/portfolio.html b/en/portfolio.html index ba460bd..13a559b 100644 --- a/en/portfolio.html +++ b/en/portfolio.html @@ -163,6 +163,7 @@Check available dates for studio booking
+Reservations can be made via email or the contact page.
We recommend booking at least 2 weeks in advance.
※ You can check real-time availability and book via Naver Place
diff --git a/gallery.html b/gallery.html index 3f83cae..de5b82f 100644 --- a/gallery.html +++ b/gallery.html @@ -98,6 +98,7 @@簡単なオンライン予約またはよくある質問をご確認ください
diff --git a/ja/gallery.html b/ja/gallery.html index 1543db5..fff67f8 100644 --- a/ja/gallery.html +++ b/ja/gallery.html @@ -104,6 +104,7 @@プロのモーションキャプチャースタジオで、クリエイティブの新たな可能性を体験してください
diff --git a/ja/portfolio.html b/ja/portfolio.html index 8904de2..7362033 100644 --- a/ja/portfolio.html +++ b/ja/portfolio.html @@ -163,6 +163,7 @@スタジオの予約可能日程をご確認ください
+※ Naverプレイスでリアルタイムのスケジュール確認および予約が可能です
diff --git a/js/schedule.js b/js/schedule.js new file mode 100644 index 0000000..8a9e453 --- /dev/null +++ b/js/schedule.js @@ -0,0 +1,179 @@ +/** + * 밍글 스튜디오 - 예약 현황 캘린더 + * Google Apps Script 프록시를 통해 캘린더 데이터를 가져와 표시 + */ +(function() { + 'use strict'; + + var APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbwoaoSmEskbJod4gR5NjLnpWSkhIDUYaGBYk0y1Q865TzaJ4gctSrTOWXxRnVa7J9AASA/exec'; + var CACHE_TTL = 30 * 60 * 1000; // 30분 + + var currentYear, currentMonth; + var calTitle = document.getElementById('calTitle'); + var calBody = document.getElementById('calBody'); + var prevBtn = document.getElementById('prevMonth'); + var nextBtn = document.getElementById('nextMonth'); + + function init() { + var now = new Date(); + currentYear = now.getFullYear(); + currentMonth = now.getMonth() + 1; + + prevBtn.addEventListener('click', function() { changeMonth(-1); }); + nextBtn.addEventListener('click', function() { changeMonth(1); }); + + renderCalendar(); + } + + function changeMonth(delta) { + currentMonth += delta; + if (currentMonth > 12) { currentMonth = 1; currentYear++; } + else if (currentMonth < 1) { currentMonth = 12; currentYear--; } + renderCalendar(); + } + + function renderCalendar() { + updateTitle(); + + var cached = getCache(currentYear, currentMonth); + if (cached !== null) { + buildGrid(cached); + } else { + // 즉시 빈 그리드 렌더링 (체감 속도 향상) + buildGrid([]); + calBody.classList.add('loading'); + fetchBookedDates(currentYear, currentMonth, function(dates) { + setCache(currentYear, currentMonth, dates); + buildGrid(dates); + calBody.classList.remove('loading'); + prefetchAdjacent(); + }); + } + } + + function prefetchAdjacent() { + var nextM = currentMonth + 1, nextY = currentYear; + if (nextM > 12) { nextM = 1; nextY++; } + if (getCache(nextY, nextM) === null) { + fetchBookedDates(nextY, nextM, function(dates) { + setCache(nextY, nextM, dates); + }); + } + } + + // --- localStorage 캐싱 --- + function cacheKey(y, m) { return 'mingle_cal_' + y + '_' + m; } + + function getCache(y, m) { + try { + var raw = localStorage.getItem(cacheKey(y, m)); + if (!raw) return null; + var obj = JSON.parse(raw); + if (Date.now() - obj.ts > CACHE_TTL) { + localStorage.removeItem(cacheKey(y, m)); + return null; + } + return obj.dates; + } catch (e) { return null; } + } + + function setCache(y, m, dates) { + try { + localStorage.setItem(cacheKey(y, m), JSON.stringify({ dates: dates, ts: Date.now() })); + } catch (e) { /* quota exceeded 등 무시 */ } + } + + // --- 제목 업데이트 --- + function updateTitle() { + var lang = (window.i18n && window.i18n.currentLang) || 'ko'; + var monthNames = { + ko: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'], + en: ['January','February','March','April','May','June','July','August','September','October','November','December'], + ja: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], + zh: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] + }; + var names = monthNames[lang] || monthNames.ko; + if (lang === 'en') { + calTitle.textContent = names[currentMonth - 1] + ' ' + currentYear; + } else if (lang === 'ja' || lang === 'zh') { + calTitle.textContent = currentYear + '年 ' + names[currentMonth - 1]; + } else { + calTitle.textContent = currentYear + '년 ' + names[currentMonth - 1]; + } + } + + // --- API 호출 --- + function fetchBookedDates(year, month, callback) { + if (!APPS_SCRIPT_URL) { callback([]); return; } + + var url = APPS_SCRIPT_URL + '?year=' + year + '&month=' + month; + fetch(url) + .then(function(res) { return res.json(); }) + .then(function(data) { callback(data.bookedDates || []); }) + .catch(function() { callback([]); }); + } + + // --- 그리드 렌더링 --- + function buildGrid(bookedDates) { + calBody.innerHTML = ''; + + var firstDay = new Date(currentYear, currentMonth - 1, 1).getDay(); + var daysInMonth = new Date(currentYear, currentMonth, 0).getDate(); + var today = new Date(); + var todayStr = today.getFullYear() + '-' + + String(today.getMonth() + 1).padStart(2, '0') + '-' + + String(today.getDate()).padStart(2, '0'); + + var bookedSet = {}; + for (var b = 0; b < bookedDates.length; b++) { + bookedSet[bookedDates[b]] = true; + } + + var fragment = document.createDocumentFragment(); + + for (var e = 0; e < firstDay; e++) { + var emptyCell = document.createElement('div'); + emptyCell.className = 'cal-cell empty'; + fragment.appendChild(emptyCell); + } + + for (var d = 1; d <= daysInMonth; d++) { + var dateStr = currentYear + '-' + + String(currentMonth).padStart(2, '0') + '-' + + String(d).padStart(2, '0'); + + var cell = document.createElement('div'); + cell.className = 'cal-cell'; + + var dayNum = document.createElement('span'); + dayNum.className = 'day-num'; + dayNum.textContent = d; + + var cellDate = new Date(currentYear, currentMonth - 1, d); + var isPast = cellDate < new Date(today.getFullYear(), today.getMonth(), today.getDate()); + + if (dateStr === todayStr) { + cell.classList.add('today'); + } else if (isPast) { + cell.classList.add('past'); + } else if (bookedSet[dateStr]) { + cell.classList.add('booked'); + } else { + cell.classList.add('available'); + } + + cell.appendChild(dayNum); + fragment.appendChild(cell); + } + + calBody.appendChild(fragment); + } + + document.addEventListener('langChanged', function() { updateTitle(); }); + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/portfolio.html b/portfolio.html index 46c7bb2..b3ff696 100644 --- a/portfolio.html +++ b/portfolio.html @@ -157,6 +157,7 @@스튜디오 예약 가능 일정을 확인하세요
+※ 네이버 플레이스를 통해 실시간 일정 확인 및 예약이 가능합니다
diff --git a/sitemap.xml b/sitemap.xml index 303b603..e38d8f6 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -38,6 +38,11 @@便捷的在线预约或查看常见问题
diff --git a/zh/gallery.html b/zh/gallery.html index 552bacc..5ced961 100644 --- a/zh/gallery.html +++ b/zh/gallery.html @@ -104,6 +104,7 @@在专业动作捕捉工作室体验创意的全新可能
diff --git a/zh/portfolio.html b/zh/portfolio.html index 93fb82b..b4c63c4 100644 --- a/zh/portfolio.html +++ b/zh/portfolio.html @@ -163,6 +163,7 @@查看工作室可预约日程
+※ 可通过Naver Place实时查看日程并预约