diff --git a/index.html b/index.html index ede0f54..7a3e832 100644 --- a/index.html +++ b/index.html @@ -5,12 +5,7 @@ Litruv - - - - - - + diff --git a/index.js b/index.js index 0c6402a..1c1bcff 100644 --- a/index.js +++ b/index.js @@ -82,8 +82,10 @@ class DOMService { fileIndex: document.getElementById('file-index'), titleText: document.querySelector('.title-text .page-title'), leftSidebar: document.querySelector('.left-sidebar'), - menuButton: document.querySelector('.menu-button') + menuButton: document.querySelector('.menu-button'), + header: document.querySelector('title-bar') // Add header element }; + this.headerOffset = 60; // Fixed header heightfsetHeight || 0; // Get header height } setupMobileMenu() { @@ -222,6 +224,18 @@ class DOMService { }); } + scrollToElement(element) { + if (!element) return; + const rect = element.getBoundingClientRect(); + const absoluteElementTop = rect.top + window.scrollY; + const middle = absoluteElementTop - (this.headerOffset + 20); // Add extra padding + + window.scrollTo({ + top: middle, + behavior: 'smooth' + }); + } + createOutlineLink(heading) { const link = document.createElement('a'); link.href = `${window.location.pathname}${window.location.search}#${heading.id}`; @@ -231,7 +245,7 @@ class DOMService { link.onclick = (e) => { e.preventDefault(); history.pushState(null, '', link.href); - heading.scrollIntoView({ behavior: 'smooth', block: 'start' }); + this.scrollToElement(heading); heading.classList.remove('highlight'); void heading.offsetWidth; heading.classList.add('highlight'); @@ -444,7 +458,8 @@ class NavigationService { window.addEventListener('popstate', async () => { const slug = new URLSearchParams(window.location.search).toString() .replace(/^=/, '').replace(/^\?/, ''); - this.eventBus.emit('navigation:requested', { slug }); + const hash = window.location.hash; + this.eventBus.emit('navigation:requested', { slug, hash }); }); document.addEventListener('click', async (e) => { @@ -510,9 +525,30 @@ class Documentation { this.indexData.documents.forEach(doc => this.domService.createFileIndexItem(doc, this.domService.elements.fileIndex)); - const urlParams = new URLSearchParams(window.location.search); - const slug = urlParams.get('') || urlParams.get('page') || 'welcome'; + // Use defaultPage from index.json + const params = new URLSearchParams(window.location.search); + let slug = ''; + if (params.has('')) { + slug = params.get(''); + } else { + for (const [key] of params) { + slug = key; + break; + } + } + slug = slug || this.indexData.defaultPage; + await this.loadDocumentBySlug(slug); + + // Handle hash after load using DOMService's scrollToElement + if (window.location.hash) { + setTimeout(() => { + const element = document.getElementById(window.location.hash.slice(1)); + if (element) { + this.domService.scrollToElement(element); + } + }, 100); + } } catch (error) { this.domService.setError(`Failed to load documentation index: ${error.message}`); } @@ -555,7 +591,17 @@ class Documentation { window._currentPath = path; - window.scrollTo({ top: 0, behavior: 'smooth' }); + // Handle hash scrolling after content is loaded + if (window.location.hash) { + const element = document.getElementById(window.location.hash.slice(1)); + if (element) { + setTimeout(() => { + this.domService.scrollToElement(element); + }, 100); + } + } else { + window.scrollTo({ top: 0, behavior: 'smooth' }); + } } catch (error) { this.domService.setError('Error loading document. Please try again.'); }