/** * Page Transitions * Tractatus Framework - Phase 3: Page Transitions * * Provides smooth fade transitions between pages for better UX */ class PageTransitions { constructor() { this.transitionDuration = 300; // milliseconds this.init(); } init() { // Add fade-in class to body on page load document.body.classList.add('page-fade-in'); // Attach click handlers to internal links this.attachLinkHandlers(); console.log('[PageTransitions] Initialized'); } attachLinkHandlers() { // Get all internal links (href starts with / or is relative) const links = document.querySelectorAll('a[href^="/"], a[href^="./"], a[href^="../"]'); links.forEach(link => { // Skip if link has target="_blank" or download attribute if (link.getAttribute('target') === '_blank' || link.hasAttribute('download')) { return; } link.addEventListener('click', (e) => { // Allow Ctrl/Cmd+click to open in new tab if (e.ctrlKey || e.metaKey || e.shiftKey) { return; } // Skip if link has hash (same-page navigation) const href = link.getAttribute('href'); if (href && href.startsWith('#')) { return; } e.preventDefault(); this.transitionToPage(link.href); }); }); console.log(`[PageTransitions] Attached handlers to ${links.length} links`); } transitionToPage(url) { // Remove fade-in, add fade-out document.body.classList.remove('page-fade-in'); document.body.classList.add('page-fade-out'); // Navigate after fade-out completes setTimeout(() => { window.location.href = url; }, this.transitionDuration); } } // Initialize on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { new PageTransitions(); }); } else { new PageTransitions(); } // Export for module systems if (typeof module !== 'undefined' && module.exports) { module.exports = PageTransitions; }