feat(projects/website): add heading permalinks

Add accessible self-links to rendered h2-h6 headings without embedding HTML in Markdown. Reveal the star marker on hover or keyboard focus, keep it visible on touch devices, and omit it from print.

Assisted-by: pi (gpt-5.6-sol)
This commit is contained in:
Gabriel Fontes
2026-08-12 03:22:30 -03:00
parent d693b272c8
commit 832fb45016
2 changed files with 45 additions and 2 deletions
+33
View File
@@ -114,6 +114,38 @@ h6 {
font-size: 1rem;
}
:is(h2, h3, h4, h5, h6) {
.heading-permalink {
display: inline-block;
margin-left: 0.4em;
color: var(--primary);
font-size: 0.55em;
line-height: 1;
opacity: 0;
text-decoration: none;
text-shadow: var(--glow-soft);
transform: scale(0.75);
transition: opacity 130ms linear, text-shadow 130ms linear, transform 130ms ease-out;
vertical-align: middle;
@media (hover: none) {
opacity: 0.65;
transform: scale(0.9);
}
@media print {
display: none;
}
}
&:hover .heading-permalink,
.heading-permalink:focus-visible {
opacity: 1;
text-shadow: var(--glow-strong);
transform: scale(1);
}
}
ul,
ol {
padding-left: 1.35rem;
@@ -797,6 +829,7 @@ body > footer {
@media (prefers-reduced-motion: reduce) {
:is(h1, h2, h3, h4, h5, h6):target,
a,
.heading-permalink,
button,
input,
select,
+12 -2
View File
@@ -88,6 +88,16 @@ var storedTheme = getTheme();
if (storedTheme) setTheme(storedTheme, false);
document.addEventListener("DOMContentLoaded", function () {
var headings = document.querySelectorAll("main :is(h2, h3, h4, h5, h6)[id]");
for (var i = 0; i < headings.length; i++) {
var permalink = document.createElement("a");
permalink.className = "heading-permalink";
permalink.href = "#" + encodeURIComponent(headings[i].id);
permalink.setAttribute("aria-label", "Permalink to " + headings[i].textContent.trim());
permalink.textContent = "✦";
headings[i].appendChild(permalink);
}
var constellation = document.querySelector(".theme-constellation");
if (!constellation) return;
@@ -95,8 +105,8 @@ document.addEventListener("DOMContentLoaded", function () {
updateThemeControls(storedTheme || "{{ site.default_scheme }}");
var buttons = constellation.querySelectorAll("[data-scheme]");
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", function () {
for (var j = 0; j < buttons.length; j++) {
buttons[j].addEventListener("click", function () {
setTheme(this.getAttribute("data-scheme"));
});
}