Conversation
vzhou842
left a comment
There was a problem hiding this comment.
overall this approach is fine and it works but it's a little problematic from a perf perspective IMO
you're passing down html through props in your React and then dynamically building an entire new DOM representation of your current page during each rerender of TableOfContents just to parse it and find the header tags, then dynamically render some stuff to make them a TOC
This can become really suboptimal if you have a really long post or a not-so-great computer. Instead, you could try a different approach:
-
[not great] just parse the
htmlstring directly instead of doingdocument.createElementand making an entire new DOM representation of the page. This is still not great because you still have to pass down thehtmlstring, seems like a big waste, also parsing the string directly can be complicated / expensive still -
[best?] generate the TOC at build time. I haven't looked into the specifics of this yet but it definitely should be possible, and I think this is the "optimal" solution. You push all the heavy computation (generating TOCs) to build time, and at actual runtime everything is very light: you only pass down the minimum data needed to render TOC to the client (very little data, just some strings really) and the render is extremely cheap.
| const AStart = `<a href=#${id} >`; | ||
| const AEnd = '</a>'; | ||
|
|
||
| node.removeAttribute('id'); | ||
|
|
||
| return AStart + node.outerHTML + AEnd; |
There was a problem hiding this comment.
nit this could all have just been one template string that reads clearer
return `<a href=#${id}>${node.outerHTML}</a>`;
This PR adds a sticky table of contents to the right of posts. It's only visible for screen sizes of
$layout-breakpoint-lg(1100px) and up (I considered shoving it under the title for smaller screens but think it looks too much of a long boi).On MBP 13":

In
Post.js, I pass in thehtmlstring to the component. Then I create anhtmldocument element in order to traverse the DOM tree and grab the header elements. For each of header elements, I remove their one child (which was thegatsby-remark-autolink-headersanchor. Then I wrap the header node in an<a>tag, with the header'sidas thehref. IMPORTANT: you have to remove theidattribute of the header or elsegatsby-remark-autolink-headersbreaks since it'll use the links in this new component. Finally, IdangerouslySetInnerHTMLthis generated string. Honestly, not very elegant at all 😬Currently, the CSS only supports up to
h4because I don't anticipate using smaller headers than that (don't even think I useh4s anywhere yet).Iffy about:
text-shadowhover -- it's not super apparent; maybe underline is better?max-width/max-height/positioning of component (I did a jank calculation)