janosh / svelte-toc

Sticky responsive table of contents component

Home Page:https://janosh.github.io/svelte-toc

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use intersection observer for highlighting active heading

rchrdnsh opened this issue · comments

Hi XD

I have my own toc workflow for a sveltkit app i'm making and I have everything taken care of up until the intersection observer to highlight the current on screen headers in the toc...trying to figure out how to do it, but have no knowledge of intersection observers or using them with svelte...looking through your code and I'm not sure where that part begins...

In my toc I am looping through an array objects:

[
  { level: 1, heading: 'Frequencies' },
  { level: 1, heading: 'Notes' },
  { level: 2, heading: 'Equivalence' },
  { level: 2, heading: 'Pitch Classes' },
  { level: 1, heading: 'The Keyboard' },
  { level: 1, heading: 'Two Zones' },
  { level: 2, heading: 'Zone 1' },
  { level: 2, heading: 'Zone 2' },
  { level: 2, heading: 'Zone 1 + Zone 2' },
  // ...etc...
]

that is generated by a custom rehype plugin traversing some markdown...

I then loop through it in my toc.svelte file:

<div class='toc-box'>
  {#each headings as {level, heading}}
    <div class='heading'>
      <a class='toc-link'
        href={`/words/${slugify(title)}#${slugify(heading)}`}
      >
        <span class='toc-link-text'>{removeTags(heading)}</span>
      </a>
    </div>
  {/each}
</div>

...and everything is almost all good when the slugified href matches the current hash and I can click around and go to hash links and all that...still not perfect and prolly should use <ul>'s and <li>'s, making my own slugify() function and it doesn't quite work right yet, but these are other issues...

The last big piece of the toc puzzle is highlighting the toc headers that are currently in the viewport...just not sure how to go about it...

...I'm looking through your code and I'm not sure where that part begins and how to adapt it to my array of objects. I also have a REPL I've put together by lifting a codepen that works and trying to make it work with svelte, but can't figure it out...

Svelte REPL:
https://svelte.dev/repl/7006d7890b964928b8f72622a3d067ac?version=3.42.5

Original Codepen:

https://codepen.io/bramus/pen/ExaEqMJ

If you don't have time or interest for this no worries, totally understand, but if you have any thoughts that you would be willing to share I am all ears :-)

Thank you!

Hey @rchrdnsh, identifying the currently viewport-intersecting heading in the ToC happens here:

([entry]) => {
activeHeading = entry.target as HTMLHeadingElement // assign intersecting node to activeHeading
},

The matching heading node is then assigned a class of active here:

class:active={activeHeading === nodes[idx]}

and styled here

nav > li.active {
color: var(--toc-active-color, orange);
}

Does that help/answer your question?

Closing for now. Please reopen if questions remain.