simonw / til

Today I Learned
https://til.simonwillison.net
Apache License 2.0
1.02k stars 81 forks source link

Fragment links on headings #81

Closed simonw closed 10 months ago

simonw commented 10 months ago

I want to be able to easily link to headings within TILs.

They already have (flawed) markup:

<h2>
  <a id="user-content-features" class="anchor" aria-hidden="true" href="#features">
    <span aria-hidden="true" class="octicon octicon-link"></span>
  </a>
  Features
</h2>

The original, un-indented version:

<h2><a id="user-content-features" class="anchor" aria-hidden="true" href="#features"><span aria-hidden="true" class="octicon octicon-link"></span></a>Features</h2>
simonw commented 10 months ago

I'm inclined to strip those out entirely, since they're broken (Link to #features but the ID is #user-content-features).

simonw commented 10 months ago

Here's where the Markdown conversation happens at the moment: https://github.com/simonw/til/blob/e9781fa844bd6066070e0a22aa7b6b535d3bad3a/build_database.py#L81-L89

simonw commented 10 months ago

API docs - https://docs.github.com/en/rest/markdown/markdown?apiVersion=2022-11-28 - nothing there that would influence the #user-content-features bit.

simonw commented 10 months ago

My ideal HTML would be more like this:

<h2 id="ref-features">Features</h2>

Or something other than ref-. Maybe anchor- ?

Then I kind of want to add the # indicators using JavaScript rather than bake them into the HTML of the page.

simonw commented 10 months ago

Prototype using JavaScript entirely:

document.querySelectorAll('h2,h3,h4,h5,h6').forEach(el => {
  let a = el.querySelector('a.anchor');
  if (!a) {
    return;
  }
  let id = a.getAttribute('id');
  el.removeChild(a);
  el.setAttribute('id', id);
  // Add '#' link
  let a2 = document.createElement('a');
  a2.style.textDecoration = 'none';
  // Pale grey
  a2.style.color = '#b7b3b3';
  a2.style.fontSize = '0.8em';
  a2.setAttribute('href', '#' + id);
  a2.innerText = '#';
  // Add a space to the h2 first
  el.appendChild(document.createTextNode(' '));
  // Add that link
  el.appendChild(a2);
})

Looks like this:

CleanShot 2023-08-19 at 07 36 56@2x
simonw commented 10 months ago

I decided to stick with #user-content-features to avoid existing links out there in the world to sections within my documents.

I implemented this entirely in JavaScript, to avoid having to add a further HTML processing step in Python - and because I'm sticking to the existing initial ID design.

simonw commented 10 months ago

Deploy will take half an hour because it's going to need to rebuild all 450 screenshots due to an (invisible) change to the entry HTML.

simonw commented 10 months ago

I'm happy with this: https://til.simonwillison.net/django/building-a-blog-in-django#user-content-url-configuration

IMG_5351