1import { define, html } from '/assets/vendor/hybrids-0b0ebcfb715640d1dc44879b91142375c3f7b28190b996216eac97a868fba07f.js'; 2 3function getSlug(text) { 4 return text 5 .toLowerCase() 6 .replace(/\s/g, '-') 7 .replace(/[^a-z0-9-]/g, ''); 8} 9 10function scroll(id) { 11 const element = document.getElementById(id); 12 element.scrollIntoView({ behavior: 'smooth' }); 13} 14 15function scrollToHeading(host, event) { 16 event.preventDefault(); 17 18 scroll(event.target.hash.slice(1)); 19 20 history.pushState(null, null, event.target.hash); 21} 22 23function toggleOpen(host, event) { 24 if (window.innerWidth < 992) { 25 host.open = !host.open; 26 } 27} 28 29define({ 30 tag: 'gh-table-of-contents', 31 headings: { 32 value: undefined, 33 connect(host, key) { 34 const headings = Array.from(host.querySelectorAll('h2')); 35 36 host[key] = headings.map((heading) => { 37 heading.id = getSlug(heading.textContent); 38 return heading.textContent; 39 }); 40 41 // Set initial scroll position 42 setTimeout(() => { 43 const hash = window.location.hash.slice(1); 44 if (hash) scroll(hash); 45 }); 46 47 const cb = (event) => { 48 const atBottom = 49 window.innerHeight + window.scrollY >= 50 document.documentElement.scrollHeight - 1; 51 52 let index = -1; 53 54 if (atBottom) { 55 index = headings.length - 1; 56 } else { 57 let current = Infinity;
58 headings.forEach((heading, i) => { 59 const { top } = heading.getBoundingClientRect(); 60 61 if (top >= 0 && top < current) { 62 index = i; 63 current = top; 64 } 65 }); 66 } 67 68 host.shadowRoot.querySelectorAll('li').forEach((li, i) => { 69 if (i === index) { 70 li.classList.add('active'); 71 } else { 72 li.classList.remove('active'); 73 } 74 }); 75 }; 76 77 window.addEventListener('scroll', cb, { passive: true }); 78 79 return () => { 80 window.removeEventListener('scroll', cb); 81 }; 82 }, 83 }, 84 open: { value: false, reflect: true }, 85 order: { value: false, reflect: true }, 86 transparent: { value: false, reflect: true }, 87 render: ({ headings }) => html` 88 <template layout="relative row content:center items:start gap:10"> 89 <div 90 id="table" 91 role="button" 92 tabindex="0" 93 layout="fixed bottom left right column padding:2:3 gap:3 layer:900" 94 layout@992px="sticky top:4 padding:3 width:300px shrink:0" 95 onclick="${toggleOpen}" 96 > 97 <div 98 layout="row content:space-between ::ds:font:display-xs ::ds:color:white ::ds:text-transform:uppercase" 99 > 100 <slot name="header"></slot> 101 <svg 102 width="16" 103 height="16"
104 viewBox="0 0 16 16" 105 fill="none" 106 xmlns="http://www.w3.org/2000/svg" 107 > 108 <path 109 d="M12 10L8 6L4 10" 110 stroke="var(--ds-color-white)" 111 stroke-width="1.5" 112 stroke-linecap="round" 113 stroke-linejoin="round" 114 /> 115 </svg> 116 </div> 117 <ol layout="relative column gap:2 margin:0 padding:0"> 118 ${headings.map( 119 (heading) => html` 120 <li layout="relative ::ds:font:body-m margin:left:3"> 121 <a href="#${getSlug(heading)}" onclick="${scrollToHeading}" 122 >${heading}</a 123 > 124 </li> 125 `, 126 )} 127 </ol> 128 </div> 129 <div layout="width:::full"><slot></slot></div> 130 </template> 131 `.css` 132 #table { 133 border-top: 1px solid var(--ds-color-gray-600, #3F4146); 134 box-shadow: 0px 0px 40px 0px rgba(0, 0, 0, 0.40); 135 background: var(--ds-color-gray-700); 136 transform: translateY(calc(100% - 50px)); 137 transition: transform 0.2s ease-in-out; 138 cursor: pointer; 139 } 140 141 :host([open]) #table { 142 cursor: default; 143 transform: translateY(0); 144 } 145 146 :host([open]) #table svg { 147 transform: rotate(180deg); 148 } 149 150 ol::before { 151 display: block; 152 position: absolute; 153 content: ''; 154 top: 0; 155 bottom: 0; 156 left: -8px; 157 width: 2px; 158 border-radius: 2px; 159 background: var(--ds-color-gray-900, #121317); 160 } 161 162 :host(:not([order])) ol { 163 list-style: none; 164 } 165 166 li { 167 transition: color 0.2s ease-in-out; 168 } 169 170 :host(:not([order])) li { 171 margin-left: 8px; 172 } 173 174 li a { 175 display: block; 176 color: inherit; 177 text-decoration: none; 178 } 179 180 li.active { 181 color: var(--ds-color-white); 182 } 183 184 li.active::before { 185 position: absolute; 186 content: ''; 187 left: -32px; 188 top: 0; 189 bottom: 0; 190 width: 2px; 191 border-radius: 2px; 192 background: var(--ds-color-primary-500); 193 } 194 195 :host(:not([order])) li.active::before { 196 left: -16px; 197 } 198 199 @media screen and (hover: hover) { 200 li:has(a:hover) { 201 color: var(--ds-color-primary-500); 202 } 203 } 204 205 @media screen and (min-width: 992px) { 206 :host(:not([order])) li { 207 margin-left: 0px; 208 } 209 210 :host([transparent]) li.active { 211 margin-left: 16px; 212 } 213 214 :host([transparent]) li.active::before { 215 left: -16px; 216 } 217 218 #table { 219 box-shadow: none; 220 border-top: none; 221 border-radius: 16px; 222 cursor: default; 223 transform: none; 224 transition: none; 225 } 226 227 :host([transparent]) #table { 228 padding: 0; 229 background: transparent; 230 } 231 232 #table svg { 233 display: none; 234 } 235 236 ol::before { 237 display: none; 238 } 239 240 li.active::before { 241 left: -48px; 242 width: 4px; 243 border-radius: 0px 2px 2px 0px; 244 } 245 } 246 `, 247});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.