diff --git a/css/style.css b/css/style.css index 1226c519a8..fc175634f4 100644 --- a/css/style.css +++ b/css/style.css @@ -1116,6 +1116,27 @@ h2 a { font-size: 16px; } +/* h2 -> h3 header links */ +.heading-link::after { + content: '#'; +} + +.heading-link { + padding-inline: 0.3em; + font-size: inherit; + text-decoration: none; + color: inherit; + opacity: 0; + transition: opacity 0.2s ease-in-out; +} + +h2:hover .heading-link, +h3:hover .heading-link, +:target .heading-link, +.heading-link:is(:hover, :focus, :focus-visible) { + opacity: 1; +} + /* search-bar desktop re-sizing */ @media all and (min-width: 950px) { .algolia-autocomplete { @@ -1736,3 +1757,4 @@ blockquote { border-bottom: 1px solid var(--border); } } + diff --git a/js/copycode.js b/js/copycode.js index 2174710746..01aac9d395 100644 --- a/js/copycode.js +++ b/js/copycode.js @@ -1,4 +1,5 @@ const codeBlocks = document.querySelectorAll("pre:has(code)"); +const headers = document.querySelectorAll('main :is(h2,h3)[id]'); codeBlocks.forEach((block) => { // Only add button if browser supports Clipboard API @@ -13,6 +14,15 @@ codeBlocks.forEach((block) => { }); }); +// add heading links +for (const heading of headers) { + const linkIcon = document.createElement('a'); + linkIcon.setAttribute('href', `#${heading.id}`); + linkIcon.classList.add('heading-link'); + linkIcon.setAttribute("aria-label", `to section ${heading.textContent.trim()}`); + heading.appendChild(linkIcon); +} + function createCopyButton() { const button = document.createElement("button"); setButtonAttributes(button, { @@ -57,3 +67,4 @@ function updateButtonState(button, statusClass, ariaLabel) { button.dataset.timerId = timer; } +