Fork of Chiri for Astro for my blog
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: clean up toc

the3ash 7967d74c 32495d5b

+18 -44
+18 -44
src/components/ui/TableOfContents.astro
··· 8 8 <div class="toc-container" id="toc"> 9 9 <nav class="toc-nav"> 10 10 <ul class="toc-list" id="toc-list"> 11 - <!-- Back to top link - always available for navigation --> 11 + <!-- Back to top link --> 12 12 <li class="toc-item toc-level-0"> 13 13 <a href="#" class="toc-link toc-title" title="Back to top" data-text="Back to top"> 14 14 Back to top ··· 19 19 { 20 20 toc.map((item) => ( 21 21 <li class={`toc-item toc-level-${item.level}`}> 22 - <a 23 - href={`#${item.id}`} 24 - class="toc-link" 25 - title={item.text} 26 - data-text={item.text} 27 - data-heading-id={item.id} 28 - > 22 + <a href={`#${item.id}`} class="toc-link" title={item.text} data-text={item.text}> 29 23 {item.text} 30 24 </a> 31 25 </li> ··· 87 81 const pageWidth = window.innerWidth 88 82 const contentWidthValue = parseFloat(contentWidth) 89 83 const widthValue = Math.min(contentWidthValue, 50) 90 - const shouldUseCustomWidth = widthValue > 25 91 - const finalWidthValue = shouldUseCustomWidth ? widthValue : 25 84 + const finalWidthValue = widthValue > 25 ? widthValue : 25 92 85 const margin = (pageWidth - finalWidthValue * 16) / 2 93 - const baseMinSpace = 11 * 16 // Base minimum space needed 94 - const minSpace = toc ? baseMinSpace + 40 : baseMinSpace 86 + const minSpace = toc ? 216 : 176 // 11rem + 40px if toc enabled 95 87 96 88 if (margin >= minSpace) { 97 89 tocContainer.style.display = 'block' 98 90 tocContainer.classList.add('fixed-position') 99 - const basePosition = margin - baseMinSpace 100 - const leftPosition = toc ? basePosition - 40 : basePosition 91 + const leftPosition = toc ? margin - 176 - 40 : margin - 176 101 92 tocContainer.style.left = `${leftPosition}px` 102 - 103 - // Update active state after TOC becomes visible 104 93 setTimeout(updateActiveTOCItem, 100) 105 94 } else { 106 95 tocContainer.style.display = 'none' ··· 127 116 e.preventDefault() 128 117 129 118 if (link.classList.contains('toc-title')) { 130 - // Back to top 131 119 window.scrollTo({ top: 0, behavior: 'smooth' }) 132 120 history.pushState(null, null, '#') 133 121 } else { 134 - // TOC item 135 122 const href = link.getAttribute('href') 136 123 if (href && href.startsWith('#')) { 137 124 const targetId = href.substring(1) ··· 139 126 if (target) { 140 127 const rect = target.getBoundingClientRect() 141 128 const scrollTop = window.pageYOffset || document.documentElement.scrollTop 142 - const offset = rect.top + scrollTop - 96 // 6rem = 96px 129 + const offset = rect.top + scrollTop - 96 143 130 window.scrollTo({ top: offset, behavior: 'smooth' }) 144 131 history.pushState(null, null, href) 145 132 } ··· 147 134 } 148 135 } 149 136 150 - // Add event listeners 151 - function addTOCEventListeners() { 152 - if (!tocContainer) return 153 - 154 - // Remove existing event listener to prevent duplicates 155 - tocContainer.removeEventListener('click', handleTOCClick) 156 - tocContainer.addEventListener('click', handleTOCClick) 157 - } 158 - 159 137 // Update active TOC item based on scroll position 160 138 function updateActiveTOCItem() { 161 139 if (!tocLinks || !headings || tocLinks.length === 0 || headings.length === 0) { ··· 163 141 } 164 142 165 143 let currentActive = null 166 - const scrollTop = window.pageYOffset + 100 // Offset for better detection 144 + const scrollTop = window.pageYOffset + 100 167 145 168 - // Find the current active heading 169 146 headings.forEach((heading, index) => { 170 147 if (index === 0 && heading.tagName === 'H1') return 171 148 ··· 177 154 } 178 155 }) 179 156 180 - // Clear all active states 181 157 tocLinks.forEach((link) => link.classList.remove('active')) 182 158 183 - // Set active state 184 159 if (currentActive && headingMap.has(currentActive)) { 185 160 const activeLink = headingMap.get(currentActive) 186 161 activeLink.classList.add('active') ··· 189 164 } 190 165 } 191 166 192 - // Initialize TOC with retry mechanism 167 + // Initialize TOC 193 168 function initializeTOC() { 194 169 if (!initDOMCache()) { 195 - // If TOC container doesn't exist yet, retry after a short delay 196 170 setTimeout(initializeTOC, 100) 197 171 return 198 172 } 199 173 200 174 adjustTOCPosition() 201 175 checkTOCVisibility() 202 - addTOCEventListeners() 176 + 177 + // Add event listeners 178 + tocContainer.removeEventListener('click', handleTOCClick) 179 + tocContainer.addEventListener('click', handleTOCClick) 180 + 203 181 updateActiveTOCItem() 204 182 } 205 183 206 184 // Debounced scroll handler 207 185 function handleScroll() { 208 186 if (scrollTimeout) clearTimeout(scrollTimeout) 209 - scrollTimeout = setTimeout(updateActiveTOCItem, 16) // ~60fps 187 + scrollTimeout = setTimeout(updateActiveTOCItem, 16) 210 188 } 211 189 212 - // Initialize with a small delay to ensure DOM is ready 190 + // Initialize 213 191 setTimeout(initializeTOC, 10) 214 192 215 193 // Event listeners 216 194 document.addEventListener('astro:page-load', () => { 217 - tocContainer = null // Reset container reference 195 + tocContainer = null 218 196 setTimeout(initializeTOC, 50) 219 - }) 220 - 221 - document.addEventListener('DOMContentLoaded', () => { 222 - if (!tocContainer) initializeTOC() 223 197 }) 224 198 225 199 window.addEventListener('resize', adjustTOCPosition) ··· 239 213 .toc-container.fixed-position { 240 214 opacity: 1; 241 215 position: fixed; 242 - top: 12rem; /* Position below BackButton */ 216 + top: 12rem; 243 217 margin-top: 0; 244 218 padding-left: 1rem; 245 219 z-index: 10; ··· 360 334 background-color: var(--text-primary); 361 335 } 362 336 363 - /* Hide on mobile and when space is limited */ 337 + /* Hide on mobile */ 364 338 @media (max-width: 768px) { 365 339 .toc-container { 366 340 display: none !important;