uu

HTML

<p class="sticky-controls"></p>
<textarea id="body_content">
[Generating a ToC | An Archaeopteryx](https://anarchaeopteryx.bearblog.dev/2025-10-20-generating-a-toc/)

Stranger, I have a better solution for you.

## Customize your dashboard  

1. Visit [https://bearblog.dev/dashboard/customise/](https://bearblog.dev/dashboard/customise/)  
2. Copy+Paste the below javascript code into the 'Dashboard footer content'  
3. Once you have written a post, click the 'Generate ToC' button (*it gets copied into your clipboard*)
4. Paste it into your post wherever you want it.

## The Code
Heavily commented for non-coders.
```html
<script type="text/javascript">

</script>
```

---

## Sample   Header 1
blah blah body text body text and what about an ###inline hashtag which should be ignored

### Sub_header 1
so let's hope that an super ## inline hashtag doesn't mess things up

#### Let's ne--st again!
We're now even deeper in the ToC

## Sample Header 2
okay but this one will only have one nested list

### Sample header 2 sub 1
testing testign 2 1

### Sample header 2 sub 2
testing testing 2 2
</textarea>

<div id="sample_table"></div>

JavaScript

// create a new button element
const toc_btn = document.createElement('button');
toc_btn.classList.add('rdb_post_restorer');
toc_btn.setAttribute('onclick', "event.preventDefault();generate_toc();");
toc_btn.innerText = 'Generate ToC';
// add the button to your 'New Post' page
document.querySelector('.sticky-controls').appendChild(toc_btn);

/** scan your post text and generate a ToC, copying it to your clipboard */
function generate_toc(){
  // HTML for the start of the ToC list
  var toc = "\n\n"+'<div class="toc">'
      +"\n"+'<h2 class="toc-head">Contents:</h2>'
      +"\n"+'<ol class="toc-list">';

  // get your post's content
  const body = document.querySelector('#body_content').value;
  // find all header occurences
  const headers_flat = body.matchAll(/^#{1,6}/gm);
  // the first header in the ToC should use '##'
  let header_size = 2;
  let started = false;
  // loop over the header occurences and generate html
  for (const match of headers_flat){
    // how many hashtags this header has
    const length = match[0].length;
    // you should not use '#' for section headers. Use `##`
    if (length < 2)continue; 
    const indent = "    ";
    const adjusted_indent = indent.repeat(length-2); 
    const li_indent = adjusted_indent + indent;
    if (length == header_size && started == true){
      toc += "</li>";
    } else if (length > header_size) {
        // add a new sub-list for sub-headers
        toc += "\n"+adjusted_indent+"<ul class=\"tol-list\">";
    } else if (length < header_size){
        // end a sub-list, escape into the parent list
        toc += "</li>\n"+adjusted_indent+"</ul></li>".repeat(header_size - length);
    } 
    header_size = length;
    started = true;

    // get the full text of the header
    const start_index = match.index + length;
    const end_index = body.indexOf("\n", match.index);
    const header_text = body.substring(start_index, end_index)
      .trim();
    const...