Files

185 lines
6.1 KiB
JavaScript

/* ============================================================
ChronoSeal Website — app.js
Core runtime: header scroll, mobile nav, scroll animations,
code copy, back-to-top, keyboard shortcuts
============================================================ */
(function () {
'use strict';
/* ---- Header scroll state ---- */
var header = document.querySelector('.navbar');
if (header) {
var onScroll = function () {
header.classList.toggle('scrolled', window.scrollY > 20);
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
}
/* ---- Enhanced Mobile nav toggle ---- */
var toggle = document.querySelector('.nav-toggle');
var navLinks = document.querySelector('.nav-links');
if (toggle && navLinks) {
var menuIcon = toggle.querySelector('i');
toggle.addEventListener('click', function () {
var isActive = navLinks.classList.contains('active');
if (isActive) {
navLinks.classList.remove('active');
if (menuIcon) {
menuIcon.classList.remove('fa-times');
menuIcon.classList.add('fa-bars');
}
} else {
navLinks.classList.add('active');
if (menuIcon) {
menuIcon.classList.remove('fa-bars');
menuIcon.classList.add('fa-times');
}
}
});
// Close nav on link click
navLinks.querySelectorAll('a').forEach(function (a) {
a.addEventListener('click', function () {
navLinks.classList.remove('active');
if (menuIcon) {
menuIcon.classList.remove('fa-times');
menuIcon.classList.add('fa-bars');
}
});
});
}
/* ---- Doc sidebar mobile toggle ---- */
var sidebarToggle = document.querySelector('.doc-sidebar-toggle');
var sidebar = document.querySelector('.doc-sidebar');
if (sidebarToggle && sidebar) {
sidebarToggle.addEventListener('click', function () {
sidebar.classList.toggle('open');
});
// Close sidebar on link click (mobile)
sidebar.querySelectorAll('.doc-nav-item').forEach(function (a) {
a.addEventListener('click', function () {
if (window.innerWidth <= 900) sidebar.classList.remove('open');
});
});
}
/* ---- Intersection Observer for Scroll Animations ---- */
if ('IntersectionObserver' in window) {
var observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' };
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all animated elements
document.querySelectorAll('.animate, .card, .stat-card, .step').forEach(function (el) {
if (!el.classList.contains('animate')) {
el.classList.add('animate');
}
observer.observe(el);
});
}
/* ---- Code block copy buttons ---- */
document.querySelectorAll('.code-copy-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var pre = btn.closest('.code-block').querySelector('pre');
if (!pre) return;
var text = pre.textContent;
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(function () {
btn.textContent = 'Copied!';
setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
});
} else {
// Fallback
var ta = document.createElement('textarea');
ta.value = text;
ta.style.cssText = 'position:fixed;left:-999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
btn.textContent = 'Copied!';
setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
}
});
});
/* ---- Back to top ---- */
var btt = document.querySelector('.back-to-top');
if (btt) {
window.addEventListener('scroll', function () {
btt.classList.toggle('visible', window.scrollY > 400);
}, { passive: true });
btt.addEventListener('click', function (e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
/* ---- Keyboard shortcut: / or Ctrl+K for search ---- */
document.addEventListener('keydown', function (e) {
if (e.key === '/' && !isInput(e.target)) {
e.preventDefault();
if (typeof ChronoSearch !== 'undefined') ChronoSearch.open();
}
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
if (typeof ChronoSearch !== 'undefined') ChronoSearch.open();
}
if (e.key === 'Escape') {
if (typeof ChronoSearch !== 'undefined') ChronoSearch.close();
}
});
function isInput(el) {
var tag = el.tagName;
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
}
/* ---- Nav dropdown (desktop hover + mobile tap) ---- */
document.querySelectorAll('.nav-dropdown').forEach(function (dd) {
var trigger = dd.querySelector('.nav-link');
if (!trigger) return;
trigger.addEventListener('click', function (e) {
if (window.innerWidth <= 768) {
e.preventDefault();
dd.classList.toggle('open');
}
});
});
/* ---- Active nav link highlight ---- */
var currentPage = window.location.pathname.split('/').pop() || 'index.html';
document.querySelectorAll('.nav-links a, .doc-nav-item').forEach(function (link) {
var href = link.getAttribute('href');
if (!href) return;
var linkPage = href.split('/').pop().split('#')[0] || 'index.html';
if (linkPage === currentPage) {
link.classList.add('active');
}
});
/* ---- Smooth anchor scroll ---- */
document.querySelectorAll('a[href^="#"]').forEach(function (a) {
a.addEventListener('click', function (e) {
var id = a.getAttribute('href').substring(1);
var target = document.getElementById(id);
if (target) {
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
history.pushState(null, '', '#' + id);
}
});
});
})();